{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "Licensed to the Apache Software Foundation (ASF) under one\n",
    "or more contributor license agreements.  See the NOTICE file\n",
    "distributed with this work for additional information\n",
    "regarding copyright ownership.  The ASF licenses this file\n",
    "to you under the Apache License, Version 2.0 (the\n",
    "\"License\"); you may not use this file except in compliance\n",
    "with the License.  You may obtain a copy of the License at\n",
    "  http://www.apache.org/licenses/LICENSE-2.0\n",
    "Unless required by applicable law or agreed to in writing,\n",
    "software distributed under the License is distributed on an\n",
    "\"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n",
    "KIND, either express or implied.  See the License for the\n",
    "specific language governing permissions and limitations\n",
    "under the License.\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from pyspark.sql import SparkSession\n",
    "from pyspark import StorageLevel\n",
    "import geopandas as gpd\n",
    "import pandas as pd\n",
    "from pyspark.sql.types import StructType\n",
    "from pyspark.sql.types import StructField\n",
    "from pyspark.sql.types import StringType\n",
    "from pyspark.sql.types import LongType\n",
    "from shapely.geometry import Point\n",
    "from shapely.geometry import Polygon\n",
    "\n",
    "from sedona.spark import *\n",
    "from sedona.spark import Envelope"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "config = (\n",
    "    SedonaContext.builder()\n",
    "    .config(\n",
    "        \"spark.jars.packages\",\n",
    "        \"uk.co.gresearch.spark:spark-extension_2.13:2.14.2-4.0\",\n",
    "    )\n",
    "    .master(\"spark://localhost:7077\")\n",
    "    .getOrCreate()\n",
    ")\n",
    "\n",
    "sedona = SedonaContext.create(config)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "sc = sedona.sparkContext"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Create SpatialRDD"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Reading to PointRDD from CSV file"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Suppose we want load the CSV file into Apache Sedona PointRDD\n",
    "```\n",
    "testattribute0,-88.331492,32.324142,testattribute1,testattribute2\n",
    "testattribute0,-88.175933,32.360763,testattribute1,testattribute2\n",
    "testattribute0,-88.388954,32.357073,testattribute1,testattribute2\n",
    "testattribute0,-88.221102,32.35078,testattribute1,testattribute2\n",
    "testattribute0,-88.323995,32.950671,testattribute1,testattribute2\n",
    "testattribute0,-88.231077,32.700812,testattribute1,testattribute2\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "                                                                                \r"
     ]
    }
   ],
   "source": [
    "point_rdd = PointRDD(sc, \"data/arealm-small.csv\", 1, FileDataSplitter.CSV, True, 10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3000"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "## Getting approximate total count\n",
    "point_rdd.approximateTotalCount"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/svg+xml": [
       "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"100.0\" height=\"100.0\" viewBox=\"-176.64696132 26.718666680000002 95.20719264000002 48.162659640000015\" preserveAspectRatio=\"xMinYMin meet\"><g transform=\"matrix(1,0,0,-1,0,101.59999300000001)\"><path fill-rule=\"evenodd\" fill=\"#66cc99\" stroke=\"#555555\" stroke-width=\"1.9041438528000003\" opacity=\"0.6\" d=\"M -84.965961,30.244859 L -84.965961,71.355134 L -173.120769,71.355134 L -173.120769,30.244859 L -84.965961,30.244859 z\" /></g></svg>"
      ],
      "text/plain": [
       "Envelope(-173.120769, -84.965961, 30.244859, 71.355134)"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# getting boundary for PointRDD or any other SpatialRDD, it returns Envelope object which inherits from\n",
    "# shapely.geometry.Polygon\n",
    "point_rdd.boundary()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# To run analyze please use function analyze\n",
    "point_rdd.analyze()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/svg+xml": [
       "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"100.0\" height=\"100.0\" viewBox=\"-176.64696132 26.718666680000002 95.20719264000002 48.162659640000015\" preserveAspectRatio=\"xMinYMin meet\"><g transform=\"matrix(1,0,0,-1,0,101.59999300000001)\"><path fill-rule=\"evenodd\" fill=\"#66cc99\" stroke=\"#555555\" stroke-width=\"1.9041438528000003\" opacity=\"0.6\" d=\"M -84.965961,30.244859 L -84.965961,71.355134 L -173.120769,71.355134 L -173.120769,30.244859 L -84.965961,30.244859 z\" /></g></svg>"
      ],
      "text/plain": [
       "Envelope(-173.120769, -84.965961, 30.244859, 71.355134)"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Finding boundary envelope for PointRDD or any other SpatialRDD, it returns Envelope object which inherits from\n",
    "# shapely.geometry.Polygon\n",
    "point_rdd.boundaryEnvelope"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2996"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Calculate number of records without duplicates\n",
    "point_rdd.countWithoutDuplicates()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "''"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Getting source epsg code\n",
    "point_rdd.getSourceEpsgCode()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "''"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Getting target epsg code\n",
    "point_rdd.getTargetEpsgCode()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "                                                                                \r"
     ]
    },
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Spatial partitioning data\n",
    "point_rdd.spatialPartitioning(GridType.KDBTREE)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Operations on RawSpatialRDD"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "rawSpatialRDD method returns RDD which consists of GeoData objects which has 2 attributes\n",
    "<li> geom: shapely.geometry.BaseGeometry </li>\n",
    "<li> userData: str </li>\n",
    "\n",
    "You can use any operations on those objects and spread across machines"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "                                                                                \r"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[Geometry: Point userData: testattribute0\ttestattribute1\ttestattribute2]"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# take firs element\n",
    "point_rdd.rawSpatialRDD.take(1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[Geometry: Point userData: testattribute0\ttestattribute1\ttestattribute2,\n",
       " Geometry: Point userData: testattribute0\ttestattribute1\ttestattribute2,\n",
       " Geometry: Point userData: testattribute0\ttestattribute1\ttestattribute2,\n",
       " Geometry: Point userData: testattribute0\ttestattribute1\ttestattribute2,\n",
       " Geometry: Point userData: testattribute0\ttestattribute1\ttestattribute2]"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# collect to Python list\n",
    "point_rdd.rawSpatialRDD.collect()[:5]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "                                                                                \r"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[111.08786851399313,\n",
       " 110.92828303170774,\n",
       " 111.1385974283527,\n",
       " 110.97450594034112,\n",
       " 110.97122518072091]"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# apply map functions, for example distance to Point(52 21)\n",
    "point_rdd.rawSpatialRDD.map(lambda x: x.geom.distance(Point(21, 52))).take(5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Transforming to GeoPandas"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Loaded data can be transformed to GeoPandas DataFrame in a few ways"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Directly from RDD"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "point_rdd_to_geo = point_rdd.rawSpatialRDD.map(\n",
    "    lambda x: [x.geom, *x.getUserData().split(\"\\t\")]\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "                                                                                \r"
     ]
    }
   ],
   "source": [
    "point_gdf = gpd.GeoDataFrame(\n",
    "    point_rdd_to_geo.collect(),\n",
    "    columns=[\"geom\", \"attr1\", \"attr2\", \"attr3\"],\n",
    "    geometry=\"geom\",\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>geom</th>\n",
       "      <th>attr1</th>\n",
       "      <th>attr2</th>\n",
       "      <th>attr3</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>POINT (-88.33149 32.32414)</td>\n",
       "      <td>testattribute0</td>\n",
       "      <td>testattribute1</td>\n",
       "      <td>testattribute2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>POINT (-88.17593 32.36076)</td>\n",
       "      <td>testattribute0</td>\n",
       "      <td>testattribute1</td>\n",
       "      <td>testattribute2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>POINT (-88.38895 32.35707)</td>\n",
       "      <td>testattribute0</td>\n",
       "      <td>testattribute1</td>\n",
       "      <td>testattribute2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>POINT (-88.22110 32.35078)</td>\n",
       "      <td>testattribute0</td>\n",
       "      <td>testattribute1</td>\n",
       "      <td>testattribute2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>POINT (-88.32399 32.95067)</td>\n",
       "      <td>testattribute0</td>\n",
       "      <td>testattribute1</td>\n",
       "      <td>testattribute2</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                         geom           attr1           attr2           attr3\n",
       "0  POINT (-88.33149 32.32414)  testattribute0  testattribute1  testattribute2\n",
       "1  POINT (-88.17593 32.36076)  testattribute0  testattribute1  testattribute2\n",
       "2  POINT (-88.38895 32.35707)  testattribute0  testattribute1  testattribute2\n",
       "3  POINT (-88.22110 32.35078)  testattribute0  testattribute1  testattribute2\n",
       "4  POINT (-88.32399 32.95067)  testattribute0  testattribute1  testattribute2"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "point_gdf[:5]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Using Adapter"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# Adapter allows you to convert geospatial data types introduced with sedona to other ones"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "spatial_df = Adapter.toDf(\n",
    "    point_rdd, [\"attr1\", \"attr2\", \"attr3\"], sedona\n",
    ").createOrReplaceTempView(\"spatial_df\")\n",
    "\n",
    "spatial_gdf = sedona.sql(\"Select attr1, attr2, attr3, geometry as geom from spatial_df\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[Stage 12:>                                                         (0 + 1) / 1]\r"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "+--------------+--------------+--------------+----------------------------+\n",
      "|attr1         |attr2         |attr3         |geom                        |\n",
      "+--------------+--------------+--------------+----------------------------+\n",
      "|testattribute0|testattribute1|testattribute2|POINT (-88.331492 32.324142)|\n",
      "|testattribute0|testattribute1|testattribute2|POINT (-88.175933 32.360763)|\n",
      "|testattribute0|testattribute1|testattribute2|POINT (-88.388954 32.357073)|\n",
      "|testattribute0|testattribute1|testattribute2|POINT (-88.221102 32.35078) |\n",
      "|testattribute0|testattribute1|testattribute2|POINT (-88.323995 32.950671)|\n",
      "+--------------+--------------+--------------+----------------------------+\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "                                                                                \r"
     ]
    }
   ],
   "source": [
    "spatial_gdf.show(5, False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "                                                                                \r"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>attr1</th>\n",
       "      <th>attr2</th>\n",
       "      <th>attr3</th>\n",
       "      <th>geom</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>testattribute0</td>\n",
       "      <td>testattribute1</td>\n",
       "      <td>testattribute2</td>\n",
       "      <td>POINT (-88.33149 32.32414)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>testattribute0</td>\n",
       "      <td>testattribute1</td>\n",
       "      <td>testattribute2</td>\n",
       "      <td>POINT (-88.17593 32.36076)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>testattribute0</td>\n",
       "      <td>testattribute1</td>\n",
       "      <td>testattribute2</td>\n",
       "      <td>POINT (-88.38895 32.35707)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>testattribute0</td>\n",
       "      <td>testattribute1</td>\n",
       "      <td>testattribute2</td>\n",
       "      <td>POINT (-88.22110 32.35078)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>testattribute0</td>\n",
       "      <td>testattribute1</td>\n",
       "      <td>testattribute2</td>\n",
       "      <td>POINT (-88.32399 32.95067)</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "            attr1           attr2           attr3                        geom\n",
       "0  testattribute0  testattribute1  testattribute2  POINT (-88.33149 32.32414)\n",
       "1  testattribute0  testattribute1  testattribute2  POINT (-88.17593 32.36076)\n",
       "2  testattribute0  testattribute1  testattribute2  POINT (-88.38895 32.35707)\n",
       "3  testattribute0  testattribute1  testattribute2  POINT (-88.22110 32.35078)\n",
       "4  testattribute0  testattribute1  testattribute2  POINT (-88.32399 32.95067)"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "gpd.GeoDataFrame(spatial_gdf.toPandas(), geometry=\"geom\")[:5]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### With DataFrame creation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [],
   "source": [
    "schema = StructType(\n",
    "    [\n",
    "        StructField(\"geometry\", GeometryType(), False),\n",
    "        StructField(\"attr1\", StringType(), False),\n",
    "        StructField(\"attr2\", StringType(), False),\n",
    "        StructField(\"attr3\", StringType(), False),\n",
    "    ]\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [],
   "source": [
    "geo_df = sedona.createDataFrame(point_rdd_to_geo, schema, verifySchema=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "                                                                                \r"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>geometry</th>\n",
       "      <th>attr1</th>\n",
       "      <th>attr2</th>\n",
       "      <th>attr3</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>POINT (-88.33149 32.32414)</td>\n",
       "      <td>testattribute0</td>\n",
       "      <td>testattribute1</td>\n",
       "      <td>testattribute2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>POINT (-88.17593 32.36076)</td>\n",
       "      <td>testattribute0</td>\n",
       "      <td>testattribute1</td>\n",
       "      <td>testattribute2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>POINT (-88.38895 32.35707)</td>\n",
       "      <td>testattribute0</td>\n",
       "      <td>testattribute1</td>\n",
       "      <td>testattribute2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>POINT (-88.22110 32.35078)</td>\n",
       "      <td>testattribute0</td>\n",
       "      <td>testattribute1</td>\n",
       "      <td>testattribute2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>POINT (-88.32399 32.95067)</td>\n",
       "      <td>testattribute0</td>\n",
       "      <td>testattribute1</td>\n",
       "      <td>testattribute2</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                     geometry           attr1           attr2           attr3\n",
       "0  POINT (-88.33149 32.32414)  testattribute0  testattribute1  testattribute2\n",
       "1  POINT (-88.17593 32.36076)  testattribute0  testattribute1  testattribute2\n",
       "2  POINT (-88.38895 32.35707)  testattribute0  testattribute1  testattribute2\n",
       "3  POINT (-88.22110 32.35078)  testattribute0  testattribute1  testattribute2\n",
       "4  POINT (-88.32399 32.95067)  testattribute0  testattribute1  testattribute2"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "gpd.GeoDataFrame(geo_df.toPandas(), geometry=\"geometry\")[:5]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Load Typed SpatialRDDs"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Currently The library supports 5 typed SpatialRDDs:\n",
    "<li> RectangleRDD </li>\n",
    "<li> PointRDD </li>\n",
    "<li> PolygonRDD </li>\n",
    "<li> LineStringRDD </li>\n",
    "<li> CircleRDD </li>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [],
   "source": [
    "rectangle_rdd = RectangleRDD(\n",
    "    sc, \"data/zcta510-small.csv\", FileDataSplitter.CSV, True, 11\n",
    ")\n",
    "point_rdd = PointRDD(sc, \"data/arealm-small.csv\", 1, FileDataSplitter.CSV, False, 11)\n",
    "polygon_rdd = PolygonRDD(\n",
    "    sc, \"data/primaryroads-polygon.csv\", FileDataSplitter.CSV, True, 11\n",
    ")\n",
    "linestring_rdd = LineStringRDD(\n",
    "    sc, \"data/primaryroads-linestring.csv\", FileDataSplitter.CSV, True\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rectangle_rdd.analyze()\n",
    "point_rdd.analyze()\n",
    "polygon_rdd.analyze()\n",
    "linestring_rdd.analyze()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Spatial Partitioning"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Apache Sedona spatial partitioning method can significantly speed up the join query. Three spatial partitioning methods are available: KDB-Tree, Quad-Tree and R-Tree. Two SpatialRDD must be partitioned by the same way."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "point_rdd.spatialPartitioning(GridType.KDBTREE)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Create Index"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Apache Sedona provides two types of spatial indexes, Quad-Tree and R-Tree. Once you specify an index type, Apache Sedona will build a local tree index on each of the SpatialRDD partition."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [],
   "source": [
    "point_rdd.buildIndex(IndexType.RTREE, True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# SpatialJoin"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Spatial join is operation which combines data based on spatial relations like:\n",
    "<li> intersects </li>\n",
    "<li> touches </li>\n",
    "<li> within </li>\n",
    "<li> etc </li>\n",
    "\n",
    "To Use Spatial Join in GeoPyspark library please use JoinQuery object, which has implemented below methods:\n",
    "```python\n",
    "SpatialJoinQuery(spatialRDD: SpatialRDD, queryRDD: SpatialRDD, useIndex: bool, considerBoundaryIntersection: bool) -> RDD\n",
    "\n",
    "DistanceJoinQuery(spatialRDD: SpatialRDD, queryRDD: SpatialRDD, useIndex: bool, considerBoundaryIntersection: bool) -> RDD\n",
    "\n",
    "spatialJoin(queryWindowRDD: SpatialRDD, objectRDD: SpatialRDD, joinParams: JoinParams) -> RDD\n",
    "\n",
    "DistanceJoinQueryFlat(spatialRDD: SpatialRDD, queryRDD: SpatialRDD, useIndex: bool, considerBoundaryIntersection: bool) -> RDD\n",
    "\n",
    "SpatialJoinQueryFlat(spatialRDD: SpatialRDD, queryRDD: SpatialRDD, useIndex: bool, considerBoundaryIntersection: bool) -> RDD\n",
    "\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Example SpatialJoinQueryFlat PointRDD with RectangleRDD "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [],
   "source": [
    "# partitioning the data\n",
    "point_rdd.spatialPartitioning(GridType.KDBTREE)\n",
    "rectangle_rdd.spatialPartitioning(point_rdd.getPartitioner())\n",
    "# building an index\n",
    "point_rdd.buildIndex(IndexType.RTREE, True)\n",
    "# Perform Spatial Join Query\n",
    "result = JoinQuery.SpatialJoinQueryFlat(point_rdd, rectangle_rdd, False, True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As result we will get RDD[GeoData, GeoData]\n",
    "It can be used like any other Python RDD. You can use map, take, collect and other functions  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "MapPartitionsRDD[63] at map at FlatPairRddConverter.scala:30"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "                                                                                \r"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[[Geometry: Polygon userData: , Geometry: Point userData: ],\n",
       " [Geometry: Polygon userData: , Geometry: Point userData: ]]"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "result.take(2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "                                                                                \r"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[[Geometry: Polygon userData: , Geometry: Point userData: ],\n",
       " [Geometry: Polygon userData: , Geometry: Point userData: ],\n",
       " [Geometry: Polygon userData: , Geometry: Point userData: ]]"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "result.collect()[:3]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "                                                                                \r"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[0.0, 0.0, 0.0, 0.0, 0.0]"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# getting distance using SpatialObjects\n",
    "result.map(lambda x: x[0].geom.distance(x[1].geom)).take(5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "                                                                                \r"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[0.026651558685001447,\n",
       " 0.026651558685001447,\n",
       " 0.026651558685001447,\n",
       " 0.057069904940998895,\n",
       " 0.057069904940998895]"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# getting area of polygon data\n",
    "result.map(lambda x: x[0].geom.area).take(5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Base on result you can create DataFrame object, using map function and build DataFrame from RDD"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [],
   "source": [
    "schema = StructType(\n",
    "    [\n",
    "        StructField(\"geom_left\", GeometryType(), False),\n",
    "        StructField(\"geom_right\", GeometryType(), False),\n",
    "    ]\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[Stage 62:===================================>                    (10 + 1) / 16]\r"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "+--------------------+--------------------+\n",
      "|           geom_left|          geom_right|\n",
      "+--------------------+--------------------+\n",
      "|POLYGON ((-87.229...|POINT (-87.204033...|\n",
      "|POLYGON ((-87.229...|POINT (-87.204299...|\n",
      "|POLYGON ((-87.229...|POINT (-87.19351 ...|\n",
      "|POLYGON ((-87.285...|POINT (-87.28468 ...|\n",
      "|POLYGON ((-87.285...|POINT (-87.215491...|\n",
      "+--------------------+--------------------+\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "                                                                                \r"
     ]
    }
   ],
   "source": [
    "# Set verifySchema to False\n",
    "spatial_join_result = result.map(lambda x: [x[0].geom, x[1].geom])\n",
    "sedona.createDataFrame(spatial_join_result, schema, verifySchema=False).show(5, True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Above code produces DataFrame with geometry Data type"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "root\n",
      " |-- geom_left: geometry (nullable = false)\n",
      " |-- geom_right: geometry (nullable = false)\n"
     ]
    }
   ],
   "source": [
    "sedona.createDataFrame(spatial_join_result, schema, verifySchema=False).printSchema()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can create DataFrame object from Spatial Pair RDD using Adapter object as follows"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[Stage 80:===================================>                    (10 + 1) / 16]\r"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "+--------------------+-----+--------------------+-----+\n",
      "|              geom_1|attr1|              geom_2|attr2|\n",
      "+--------------------+-----+--------------------+-----+\n",
      "|POLYGON ((-87.229...|     |POINT (-87.204033...|     |\n",
      "|POLYGON ((-87.229...|     |POINT (-87.204299...|     |\n",
      "|POLYGON ((-87.229...|     |POINT (-87.19351 ...|     |\n",
      "|POLYGON ((-87.285...|     |POINT (-87.28468 ...|     |\n",
      "|POLYGON ((-87.285...|     |POINT (-87.215491...|     |\n",
      "+--------------------+-----+--------------------+-----+\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "                                                                                \r"
     ]
    }
   ],
   "source": [
    "Adapter.toDf(result, [\"attr1\"], [\"attr2\"], sedona).show(5, True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This also produce DataFrame with geometry DataType "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[Stage 89:==========================================>             (12 + 1) / 16]\r"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "root\n",
      " |-- geom_1: geometry (nullable = true)\n",
      " |-- attr1: string (nullable = true)\n",
      " |-- geom_2: geometry (nullable = true)\n",
      " |-- attr2: string (nullable = true)\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "                                                                                \r"
     ]
    }
   ],
   "source": [
    "Adapter.toDf(result, [\"attr1\"], [\"attr2\"], sedona).printSchema()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can create RDD which will be of type RDD[GeoData, List[GeoData]]\n",
    "We can for example calculate number of Points within some polygon data"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To do that we can use code specified below"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [],
   "source": [
    "point_rdd.spatialPartitioning(GridType.KDBTREE)\n",
    "rectangle_rdd.spatialPartitioning(point_rdd.getPartitioner())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [],
   "source": [
    "spatial_join_result_non_flat = JoinQuery.SpatialJoinQuery(\n",
    "    point_rdd, rectangle_rdd, False, True\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [],
   "source": [
    "# number of point for each polygon\n",
    "number_of_points = spatial_join_result_non_flat.map(\n",
    "    lambda x: [x[0].geom, x[1].__len__()]\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [],
   "source": [
    "schema = StructType(\n",
    "    [\n",
    "        StructField(\"geometry\", GeometryType(), False),\n",
    "        StructField(\"number_of_points\", LongType(), False),\n",
    "    ]\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "                                                                                \r"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "+--------------------+----------------+\n",
      "|            geometry|number_of_points|\n",
      "+--------------------+----------------+\n",
      "|POLYGON ((-86.749...|               4|\n",
      "|POLYGON ((-87.229...|               7|\n",
      "|POLYGON ((-87.114...|              15|\n",
      "|POLYGON ((-87.082...|              12|\n",
      "|POLYGON ((-86.697...|               1|\n",
      "|POLYGON ((-86.816...|               6|\n",
      "|POLYGON ((-87.285...|              26|\n",
      "|POLYGON ((-87.105...|              15|\n",
      "|POLYGON ((-86.860...|              12|\n",
      "|POLYGON ((-87.092...|               5|\n",
      "+--------------------+----------------+\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "                                                                                \r"
     ]
    }
   ],
   "source": [
    "sedona.createDataFrame(number_of_points, schema, verifySchema=False).show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# KNNQuery"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Spatial KNNQuery is operation which help us find answer which k number of geometries lays closest to other geometry.\n",
    "\n",
    "For Example:\n",
    "    5 closest Shops to your home. To use Spatial KNNQuery please use object \n",
    "<b> KNNQuery </b> which has one method:\n",
    "```python\n",
    "SpatialKnnQuery(spatialRDD: SpatialRDD, originalQueryPoint: BaseGeometry, k: int,  useIndex: bool)-> List[GeoData]\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Finds 5 closest points from PointRDD to given Point"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [],
   "source": [
    "result = KNNQuery.SpatialKnnQuery(point_rdd, Point(-84.01, 34.01), 5, False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[Geometry: Point userData: ,\n",
       " Geometry: Point userData: ,\n",
       " Geometry: Point userData: ,\n",
       " Geometry: Point userData: ,\n",
       " Geometry: Point userData: ]"
      ]
     },
     "execution_count": 49,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "result"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As Reference geometry you can also use Polygon or LineString object"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "                                                                                \r"
     ]
    }
   ],
   "source": [
    "polygon = Polygon(\n",
    "    [\n",
    "        (-84.237756, 33.904859),\n",
    "        (-84.237756, 34.090426),\n",
    "        (-83.833011, 34.090426),\n",
    "        (-83.833011, 33.904859),\n",
    "        (-84.237756, 33.904859),\n",
    "    ]\n",
    ")\n",
    "polygons_nearby = KNNQuery.SpatialKnnQuery(polygon_rdd, polygon, 5, False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[Geometry: Polygon userData: ,\n",
       " Geometry: Polygon userData: ,\n",
       " Geometry: Polygon userData: ,\n",
       " Geometry: Polygon userData: ,\n",
       " Geometry: Polygon userData: ]"
      ]
     },
     "execution_count": 51,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "polygons_nearby"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'POLYGON ((-83.993559 34.087259, -83.993559 34.131247, -83.959903 34.131247, -83.959903 34.087259, -83.993559 34.087259))'"
      ]
     },
     "execution_count": 52,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "polygons_nearby[0].geom.wkt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# RangeQuery"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A spatial range query takes as input a range query window and an SpatialRDD and returns all geometries that intersect / are fully covered by the query window. \n",
    "RangeQuery has one method:\n",
    "\n",
    "```python\n",
    "SpatialRangeQuery(self, spatialRDD: SpatialRDD, rangeQueryWindow: BaseGeometry, considerBoundaryIntersection: bool, usingIndex: bool) -> RDD\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sedona.spark.core.geom.envelope import Envelope"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [],
   "source": [
    "query_envelope = Envelope(-85.01, -60.01, 34.01, 50.01)\n",
    "\n",
    "result_range_query = RangeQuery.SpatialRangeQuery(\n",
    "    linestring_rdd, query_envelope, False, False\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "MapPartitionsRDD[127] at map at GeometryRddConverter.scala:30"
      ]
     },
     "execution_count": 55,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "result_range_query"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[Geometry: LineString userData: ,\n",
       " Geometry: LineString userData: ,\n",
       " Geometry: LineString userData: ,\n",
       " Geometry: LineString userData: ,\n",
       " Geometry: LineString userData: ,\n",
       " Geometry: LineString userData: ]"
      ]
     },
     "execution_count": 56,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "result_range_query.take(6)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Creating DataFrame from result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [],
   "source": [
    "schema = StructType([StructField(\"geometry\", GeometryType(), False)])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "+--------------------+\n",
      "|            geometry|\n",
      "+--------------------+\n",
      "|LINESTRING (-72.1...|\n",
      "|LINESTRING (-72.4...|\n",
      "|LINESTRING (-72.4...|\n",
      "|LINESTRING (-73.4...|\n",
      "|LINESTRING (-73.6...|\n",
      "+--------------------+\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "                                                                                \r"
     ]
    }
   ],
   "source": [
    "sedona.createDataFrame(\n",
    "    result_range_query.map(lambda x: [x.geom]), schema, verifySchema=False\n",
    ").show(5, True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Load From other Formats"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "GeoPyspark allows to load the data from other Data formats like:\n",
    "<li> GeoJSON </li>\n",
    "<li> Shapefile </li>\n",
    "<li> WKB </li>\n",
    "<li> WKT </li>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {},
   "outputs": [],
   "source": [
    "## ShapeFile - load to SpatialRDD"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {},
   "outputs": [],
   "source": [
    "shape_rdd = ShapefileReader.readToGeometryRDD(sc, \"data/polygon\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<sedona.core.SpatialRDD.spatial_rdd.SpatialRDD at 0x7f468e4bacd0>"
      ]
     },
     "execution_count": 62,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "shape_rdd"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "+--------------------+\n",
      "|            geometry|\n",
      "+--------------------+\n",
      "|MULTIPOLYGON (((1...|\n",
      "|MULTIPOLYGON (((-...|\n",
      "|MULTIPOLYGON (((1...|\n",
      "|POLYGON ((118.362...|\n",
      "|MULTIPOLYGON (((-...|\n",
      "+--------------------+\n"
     ]
    }
   ],
   "source": [
    "Adapter.toDf(shape_rdd, sedona).show(5, True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {},
   "outputs": [],
   "source": [
    "## GeoJSON - load to SpatialRDD"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "{ \"type\": \"Feature\", \"properties\": { \"STATEFP\": \"01\", \"COUNTYFP\": \"077\", \"TRACTCE\": \"011501\", \"BLKGRPCE\": \"5\", \"AFFGEOID\": \"1500000US010770115015\", \"GEOID\": \"010770115015\", \"NAME\": \"5\", \"LSAD\": \"BG\", \"ALAND\": 6844991, \"AWATER\": 32636 }, \"geometry\": { \"type\": \"Polygon\", \"coordinates\": [ [ [ -87.621765, 34.873444 ], [ -87.617535, 34.873369 ], [ -87.6123, 34.873337 ], [ -87.604049, 34.873303 ], [ -87.604033, 34.872316 ], [ -87.60415, 34.867502 ], [ -87.604218, 34.865687 ], [ -87.604409, 34.858537 ], [ -87.604018, 34.851336 ], [ -87.603716, 34.844829 ], [ -87.603696, 34.844307 ], [ -87.603673, 34.841884 ], [ -87.60372, 34.841003 ], [ -87.603879, 34.838423 ], [ -87.603888, 34.837682 ], [ -87.603889, 34.83763 ], [ -87.613127, 34.833938 ], [ -87.616451, 34.832699 ], [ -87.621041, 34.831431 ], [ -87.621056, 34.831526 ], [ -87.62112, 34.831925 ], [ -87.621603, 34.8352 ], [ -87.62158, 34.836087 ], [ -87.621383, 34.84329 ], [ -87.621359, 34.844438 ], [ -87.62129, 34.846387 ], [ -87.62119, 34.85053 ], [ -87.62144, 34.865379 ], [ -87.621765, 34.873444 ] ] ] } },\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {},
   "outputs": [],
   "source": [
    "geo_json_rdd = GeoJsonReader.readToGeometryRDD(sc, \"data/testPolygon.json\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<sedona.core.SpatialRDD.spatial_rdd.SpatialRDD at 0x7f468e4c94f0>"
      ]
     },
     "execution_count": 66,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "geo_json_rdd"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[Stage 111:>                                                        (0 + 1) / 1]\r"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "+--------------------+-------+--------+-------+--------+--------------------+------------+----+----+--------+\n",
      "|            geometry|STATEFP|COUNTYFP|TRACTCE|BLKGRPCE|            AFFGEOID|       GEOID|NAME|LSAD|   ALAND|\n",
      "+--------------------+-------+--------+-------+--------+--------------------+------------+----+----+--------+\n",
      "|POLYGON ((-87.621...|     01|     077| 011501|       5|1500000US01077011...|010770115015|   5|  BG| 6844991|\n",
      "|POLYGON ((-85.719...|     01|     045| 021102|       4|1500000US01045021...|010450211024|   4|  BG|11360854|\n",
      "|POLYGON ((-86.000...|     01|     055| 001300|       3|1500000US01055001...|010550013003|   3|  BG| 1378742|\n",
      "|POLYGON ((-86.574...|     01|     089| 001700|       2|1500000US01089001...|010890017002|   2|  BG| 1040641|\n",
      "|POLYGON ((-85.382...|     01|     069| 041400|       1|1500000US01069041...|010690414001|   1|  BG| 8243574|\n",
      "+--------------------+-------+--------+-------+--------+--------------------+------------+----+----+--------+\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "                                                                                \r"
     ]
    }
   ],
   "source": [
    "Adapter.toDf(geo_json_rdd, sedona).drop(\"AWATER\").show(5, True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {},
   "outputs": [],
   "source": [
    "## WKT - loading to SpatialRDD"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "metadata": {},
   "outputs": [],
   "source": [
    "wkt_rdd = WktReader.readToGeometryRDD(sc, \"data/county_small.tsv\", 0, True, False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<sedona.core.SpatialRDD.spatial_rdd.SpatialRDD at 0x7f468e2fd280>"
      ]
     },
     "execution_count": 70,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "wkt_rdd"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "root\n",
      " |-- geometry: geometry (nullable = true)\n"
     ]
    }
   ],
   "source": [
    "Adapter.toDf(wkt_rdd, sedona).printSchema()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[Stage 113:>                                                        (0 + 1) / 1]\r"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "+--------------------+\n",
      "|            geometry|\n",
      "+--------------------+\n",
      "|POLYGON ((-97.019...|\n",
      "|POLYGON ((-123.43...|\n",
      "|POLYGON ((-104.56...|\n",
      "|POLYGON ((-96.910...|\n",
      "|POLYGON ((-98.273...|\n",
      "+--------------------+\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "                                                                                \r"
     ]
    }
   ],
   "source": [
    "Adapter.toDf(wkt_rdd, sedona).show(5, True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 73,
   "metadata": {},
   "outputs": [],
   "source": [
    "## WKB - load to SpatialRDD"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "metadata": {},
   "outputs": [],
   "source": [
    "wkb_rdd = WkbReader.readToGeometryRDD(sc, \"data/county_small_wkb.tsv\", 0, True, False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 75,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "+--------------------+\n",
      "|            geometry|\n",
      "+--------------------+\n",
      "|POLYGON ((-97.019...|\n",
      "|POLYGON ((-123.43...|\n",
      "|POLYGON ((-104.56...|\n",
      "|POLYGON ((-96.910...|\n",
      "|POLYGON ((-98.273...|\n",
      "+--------------------+\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "                                                                                \r"
     ]
    }
   ],
   "source": [
    "Adapter.toDf(wkb_rdd, sedona).show(5, True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Converting RDD Spatial join result to DF directly, avoiding jvm python serde"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 76,
   "metadata": {},
   "outputs": [],
   "source": [
    "point_rdd.spatialPartitioning(GridType.KDBTREE)\n",
    "rectangle_rdd.spatialPartitioning(point_rdd.getPartitioner())\n",
    "# building an index\n",
    "point_rdd.buildIndex(IndexType.RTREE, True)\n",
    "# Perform Spatial Join Query\n",
    "result = JoinQueryRaw.SpatialJoinQueryFlat(point_rdd, rectangle_rdd, False, True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "metadata": {},
   "outputs": [],
   "source": [
    "# without passing column names, the result will contain only two geometries columns\n",
    "geometry_df = Adapter.toDf(result, sedona)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 78,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "root\n",
      " |-- leftgeometry: geometry (nullable = true)\n",
      " |-- rightgeometry: geometry (nullable = true)\n"
     ]
    }
   ],
   "source": [
    "geometry_df.printSchema()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 79,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "                                                                                \r"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "+--------------------+--------------------+\n",
      "|        leftgeometry|       rightgeometry|\n",
      "+--------------------+--------------------+\n",
      "|POLYGON ((-87.092...|POINT (-86.94719 ...|\n",
      "|POLYGON ((-86.749...|POINT (-86.736302...|\n",
      "|POLYGON ((-86.749...|POINT (-86.735506...|\n",
      "|POLYGON ((-86.749...|POINT (-86.68645 ...|\n",
      "|POLYGON ((-86.749...|POINT (-86.675405...|\n",
      "+--------------------+--------------------+\n"
     ]
    }
   ],
   "source": [
    "geometry_df.show(5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Row(leftgeometry=<POLYGON ((-87.093 34.264, -87.093 34.422, -86.764 34.422, -86.764 34.264, -...>, rightgeometry=<POINT (-86.947 34.29)>)"
      ]
     },
     "execution_count": 80,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "geometry_df.collect()[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Passing column names"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 81,
   "metadata": {},
   "outputs": [],
   "source": [
    "geometry_df = Adapter.toDf(result, [\"left_user_data\"], [\"right_user_data\"], sedona)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 82,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "+--------------------+--------------+--------------------+---------------+\n",
      "|        leftgeometry|left_user_data|       rightgeometry|right_user_data|\n",
      "+--------------------+--------------+--------------------+---------------+\n",
      "|POLYGON ((-87.092...|              |POINT (-86.94719 ...|           null|\n",
      "|POLYGON ((-86.749...|              |POINT (-86.736302...|           null|\n",
      "|POLYGON ((-86.749...|              |POINT (-86.735506...|           null|\n",
      "|POLYGON ((-86.749...|              |POINT (-86.68645 ...|           null|\n",
      "|POLYGON ((-86.749...|              |POINT (-86.675405...|           null|\n",
      "+--------------------+--------------+--------------------+---------------+\n"
     ]
    }
   ],
   "source": [
    "geometry_df.show(5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Converting RDD Spatial join result to DF directly, avoiding jvm python serde"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 83,
   "metadata": {},
   "outputs": [],
   "source": [
    "query_envelope = Envelope(-85.01, -60.01, 34.01, 50.01)\n",
    "\n",
    "result_range_query = RangeQueryRaw.SpatialRangeQuery(\n",
    "    linestring_rdd, query_envelope, False, False\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 84,
   "metadata": {},
   "outputs": [],
   "source": [
    "# converting to df\n",
    "gdf = Adapter.toDf(result_range_query, sedona)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 85,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "+--------------------+\n",
      "|            geometry|\n",
      "+--------------------+\n",
      "|LINESTRING (-72.1...|\n",
      "|LINESTRING (-72.4...|\n",
      "|LINESTRING (-72.4...|\n",
      "|LINESTRING (-73.4...|\n",
      "|LINESTRING (-73.6...|\n",
      "+--------------------+\n"
     ]
    }
   ],
   "source": [
    "gdf.show(5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "root\n",
      " |-- geometry: geometry (nullable = true)\n"
     ]
    }
   ],
   "source": [
    "gdf.printSchema()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 87,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Passing column names\n",
    "# converting to df\n",
    "gdf_with_columns = Adapter.toDf(result_range_query, sedona, [\"_c1\"])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 88,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "+--------------------+---+\n",
      "|            geometry|_c1|\n",
      "+--------------------+---+\n",
      "|LINESTRING (-72.1...|   |\n",
      "|LINESTRING (-72.4...|   |\n",
      "|LINESTRING (-72.4...|   |\n",
      "|LINESTRING (-73.4...|   |\n",
      "|LINESTRING (-73.6...|   |\n",
      "+--------------------+---+\n"
     ]
    }
   ],
   "source": [
    "gdf_with_columns.show(5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 89,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "root\n",
      " |-- geometry: geometry (nullable = true)\n",
      " |-- _c1: string (nullable = true)\n"
     ]
    }
   ],
   "source": [
    "gdf_with_columns.printSchema()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.18"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
